package com.zc.utils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
import java.util.Date;
import java.util.UUID;

/**
 * @description:
 * @author: cong
 * @create: 2024/8/1
 */
public class JwtUtil {
    // 令牌过期时间 60 * 60 * 1000L = 1小时
    public static final Long JWT_TTL = 60 * 60 * 1000L;

    // 秘钥
    public static final String JWT_KEY = "cong";

    public static String getUUID() {
        return UUID.randomUUID().toString().replaceAll("-", "");
    }

    /**
     * 创建JWT令牌
     *
     * @param subject JWT的主题，通常用于标识令牌的主要用户或实体
     * @return 返回生成的JWT令牌字符串
     */
    public static String createJwt(String subject) {
        // 获取JWT构建器，使用指定的主题、过期时间和唯一标识符
        JwtBuilder jwtBuilder = getJwtBuilder(subject, null, getUUID());
        // 将构建的JWT对象压缩为紧凑的JWT字符串
        return jwtBuilder.compact();
    }

    /**
     * 创建JWT令牌
     *
     * @param subject JWT的主题，通常用于标识令牌的主要用户或实体
     * @return 返回生成的JWT令牌字符串
     */
    public static String createJwt(String subject, long ttlMillis) {
        // 获取JWT构建器，使用指定的主题、过期时间和唯一标识符
        JwtBuilder jwtBuilder = getJwtBuilder(subject, ttlMillis, getUUID());
        // 将构建的JWT对象压缩为紧凑的JWT字符串
        return jwtBuilder.compact();
    }


    private static JwtBuilder getJwtBuilder(String subject, Long ttlMillis, String uuid) {
        SecretKey key = generateKey();

        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        if (ttlMillis == null) {
            ttlMillis = JwtUtil.JWT_TTL;
        }

        Date expireDate = new Date(nowMillis + ttlMillis);
        return Jwts.builder().setId(uuid)
                .setSubject(subject)
                .setIssuer("cong") // 签发者
                .setIssuedAt(now) // 签发事件
                .setExpiration(expireDate)
                .signWith(key);
    }

    /**
     * 生成SecretKey对象，用于JWT的签名和验证
     * <p>
     * 此方法首先对预定义的JWT密钥字符串进行Base64解码，以获取原始的密钥字节
     * 然后，创建一个新的字节数组，从解码后的密钥中复制最多256字节到新数组中
     * 这一步是为了确保密钥长度符合HmacSHA256算法的要求
     * 最后，使用处理后的字节数组创建并返回一个SecretKeySpec对象，指定其用途为HmacSHA256
     *
     * @return SecretKey 返回生成的密钥对象，用于JWT的处理
     */
    private static SecretKey generateKey() {
        // 对JWT密钥进行Base64解码
        byte[] decode = Base64.getDecoder().decode(JWT_KEY);

        // 创建一个最大长度为256字节的新数组，以适配HmacSHA256算法的要求
        byte[] bytes = new byte[256];
        // 复制解码后的密钥字节到新数组中，最多复制256字节
        System.arraycopy(decode, 0, bytes, 0, Math.min(decode.length, bytes.length));
        // 使用处理后的字节数组创建SecretKeySpec对象，指定其用途为HmacSHA256
        return new SecretKeySpec(bytes, 0, bytes.length, "HmacSHA256");
    }

    /**
     * 解析JWT令牌
     * @param jwt JWT令牌
     * @return {@link Claims }
     */
    public static Claims parseJWT(String jwt) {
        SecretKey key = generateKey();
        return Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(jwt).getBody();
    }
}
